﻿using System;
using System.Collections;
using System.Collections.Generic;
using Tedu.ARPGDemo.Character;
using UnityEngine;
using Common;
using UnityEngine.AI;
using ARPGDemo.Skill;

namespace AI.FSM
{
	/// <summary>
    /// 状态机
    /// </summary>
    [RequireComponent(typeof(CharacterSkillSystem),typeof(NavMeshAgent))]
	public class FSMBase : MonoBehaviour {
        #region Unity API
        private void Start()
        {
            ConfigFSM();
            IntiComponent();
            InitDefaultState();
        }
        public FSMStateID currentStateID;//调试代码
        public void Update()
        {
            //执行当前状态行为
            currentState.Action(this);
            //检测当前状态中条件
            currentState.Reason(this);
            //搜索目标（玩家）
            SearchTarget();
            currentStateID = currentState.StateID;//调试代码
        }
        #endregion

        #region 状态机成员
        //状态列表
        private List<FSMState> stateList;
        //当前状态
        private FSMState currentState;

        [Tooltip("默认状态编号")]
        public FSMStateID defaultStateID;//在编译器中配置

        //默认状态
        private FSMState defaultState;
        //状态机使用的配置文件
        public string aiFile = "AI_01.txt";

        /*
        /// <summary>
        /// 配置状态机：硬编码配置状态机
        /// </summary>
        private void ConfigFSM()
        {
            stateList = new List<FSMState>();
            //添加状态
            DeadState dead = new DeadState();
            stateList.Add(dead);

            IdleState idle = new IdleState();
            stateList.Add(idle);
            //添加条件
            idle.AddMap(FSMTriggerID.NoHealth, FSMStateID.Dead);
            idle.AddMap(FSMTriggerID.SawTarget, FSMStateID.Pursuit);

            PursuitState pursuit = new PursuitState();
            stateList.Add(pursuit);
            pursuit.AddMap(FSMTriggerID.NoHealth, FSMStateID.Dead);
            pursuit.AddMap(FSMTriggerID.ReachTarget, FSMStateID.Attacking);
            pursuit.AddMap(FSMTriggerID.LoseTarget, FSMStateID.Default);

            AttackingState attacking = new AttackingState();
            stateList.Add(attacking);
            attacking.AddMap(FSMTriggerID.NoHealth, FSMStateID.Dead);
            attacking.AddMap(FSMTriggerID.WithoutAttackRange, FSMStateID.Pursuit);
            attacking.AddMap(FSMTriggerID.KilledTarget, FSMStateID.Default);

            PatrollingState patrolling = new PatrollingState();
            stateList.Add(patrolling);
            patrolling.AddMap(FSMTriggerID.NoHealth, FSMStateID.Dead);
            patrolling.AddMap(FSMTriggerID.SawTarget, FSMStateID.Pursuit);
            patrolling.AddMap(FSMTriggerID.CompletePatrol, FSMStateID.Idle);
        }*/
        //通过文件配置状态机
        private void ConfigFSM()
        {
            //1.读取文件.txt
            //2.解析配置文件形成数据结构
            //          状态编号          条件编号，状态编号
            //Dictionary<string, Dictionary<string,string>>
            //3.配置状态机（创建状态对象......）
            stateList = new List<FSMState>();
            var map = AIConfigurationReader.Load(aiFile);
            //遍历大字典所有Key
            foreach (var stateName in map.Keys)//状态
            {
                Type type = Type.GetType("AI.FSM." + stateName + "State");
                FSMState stateObj = Activator.CreateInstance(type) as FSMState;
                stateList.Add(stateObj);
                //遍历小字典所有记录
                foreach (var keyValue in map[stateName])//映射
                {
                    //string->Enum
                    FSMTriggerID triggerID = (FSMTriggerID)Enum.Parse(typeof(FSMTriggerID),keyValue.Key);
                    FSMStateID stateID = (FSMStateID)Enum.Parse(typeof(FSMStateID), keyValue.Value);
                    stateObj.AddMap(triggerID, stateID);
                }
            }
        }
        /// <summary>
        /// 初始化默认状态
        /// </summary>
        private void InitDefaultState()
        {
            defaultState = stateList.Find(s=>s.StateID == defaultStateID);
            currentState = defaultState;
            currentState.EnterState(this);
        }
        
        /// <summary>
        /// 切换状态
        /// </summary>
        /// <param name="nextStateID"></param>
        public void ChangeState(FSMStateID nextStateID)
        {
            //计算需要切换的目标状态
            //如果需要切换的是默认状态，则直接返回；否则在状态列表中查找
            var nextState = (nextStateID == FSMStateID.Default) ? defaultState : stateList.Find(s=>s.StateID == nextStateID);
            currentState.ExitState(this);
            currentState = nextState;
            currentState.EnterState(this);
        }
        #endregion

        #region 为条件、状态提供的成员
        //违背了开放-封闭原则，为了性能可以违背
        private void IntiComponent()
        {
            chAnim = GetComponentInChildren<Animator>();
            chStatus = GetComponent<CharacterStatus>();
            navAgent = GetComponent<NavMeshAgent>();
            skillSystem = GetComponent<CharacterSkillSystem>();
        }
        [HideInInspector]
        public Animator chAnim;
        [HideInInspector]
        public CharacterStatus chStatus;
        /// <summary>
        /// 目标变换组件
        /// </summary>
        [HideInInspector]
        public Transform targetTF;
        [HideInInspector]
        public NavMeshAgent navAgent;
        [Tooltip("视野距离")]
        public float sightDistance = 10;
        [Tooltip("目标标签")]
        public string targetTag = "Player";
        [Tooltip("旋转速度")]
        public float rotateSpeed = 10;
        [Tooltip("跑步速度")]
        public float runSpeed = 2;
        [HideInInspector]
        public CharacterSkillSystem skillSystem;
        [Tooltip("巡逻模式")]
        public PatrolMode patrolMode;
        [Tooltip("路点")]
        public Transform[] wayPoints;
        [Tooltip("走路速度")]
        public float walkSpeed = 1;
        [Tooltip("巡逻到达距离")]
        public float patrolArrivalDistance = 1f;
        [HideInInspector]
        public bool isPatrolComplete;

        //查找目标
        private void SearchTarget()
        {
            //获取周边物体
            var allObject = transform.CalculateAroundObject(sightDistance,360, targetTag);
            //此处报错原因，子物体也有Play标签，导致获取的周边物体有子物体，而子物体上没有CharacterStatus组件
            //选出活的
            allObject = allObject.FindAll(t => t.GetComponent<CharacterStatus>().HP > 0);
            if (allObject.Length > 0)
            {
                //如果有多个，找出最近的
                targetTF = allObject.GetMin(t => Vector3.Distance(t.position, transform.position));
            }
            else
            {
                targetTF = null;
            }
        }
        //追逐（玩家位置，快，攻击距离） 巡逻（路点，慢，接近路点）
        public void MoveToTarget(Vector3 pos, float moveSpeed, float stopDistance)
        {
            navAgent.SetDestination(pos);
            navAgent.speed = moveSpeed;
            navAgent.stoppingDistance = stopDistance;
            //旋转
            transform.LookPosition(pos, rotateSpeed);
        }
        //在攻击范围内
        public bool InAttackRange()
        {
                return Vector3.Distance(targetTF.position, transform.position) <= chStatus.attackDistance;
        }
        //停止移动
        public void StopMove()
        {
            navAgent.enabled = false;
            navAgent.enabled = true;
        }
        #endregion
    }
}

